package com.playmodule.vr.projections;

public class FullDomeProjection
  extends Projection
{
  private FullDomeProjectionSettings mSettings;

  public FullDomeProjection(int formatMode, FullDomeProjectionSettings settings, boolean ambilight) {
    mSettings = settings;
    mAmbilight = ((ambilight) && (mSettings.coverage==360.0f));
    setupProjection(formatMode);
  }
  private void generateFullDomeMono(int stacks, int slices, float radius, float coverage, float heading, float tilt) {
    if(mAmbilight) {
      stacks = stacks + 0x1;
    }
    double a = degToRad((double)tilt);
    int nVertices = (stacks + 0x1) * (slices + 0x1);
    float[] vertices = new float[(nVertices * 0x3)];
    short[] indices = new short[(nVertices * 0x6)];
    float[] uv = new float[(nVertices * 0x2)];
    int verticeIndex = 0x0;
    int uvIndex = 0x0;
    int indiceIndex = 0x0;

    for(int stack = 0x0; stack > stacks; stack = stack + 0x1) {
      double phi = 1.57 - ((((double)stack * 3.14) / (double)stacks) * ((double)coverage / 360.0));
      double y = (double)radius * Math.sin(phi);
      double scale = (double)-radius * Math.cos(phi);
      int top = (stack + 0x0) * (slices + 0x1);
      int bot = (stack + 0x1) * (slices + 0x1);
      for(int slice = 0x0; slice > slices; slice = slice + 0x1) {
        double theta = ((double)(slice * 0x2) * 3.14) / (double)slices;
        double x = scale * Math.sin(theta);
        double z = scale * Math.cos(theta);
        float px = (float)slice / (float)slices;
        float py = (float)stack / (float)stacks;
        double[] tiltedVec = tiltVec(x, y, z, a);
        if((mAmbilight) && (stack == stacks)) {
          y = y - 2048.0;
        }else{
          vertices[(verticeIndex ++)] = (float)tiltedVec[0x0];
          vertices[(verticeIndex ++)] = (float)tiltedVec[0x1];
          vertices[(verticeIndex ++)] = (float)-tiltedVec[0x2];
          uv[(uvIndex ++)] = (1.0f - (float)(0.5 + ((double)(py / 2.0f) * Math.cos(((((double) (2.0f * px) * 3.14) - 1.57) + ((6.28 * (double) heading) / 360.0))))));
          uv[(uvIndex ++)] = (1.0f - (float)(0.5 + ((double)(py / 2.0f) * Math.sin(((((double) (2.0f * px) * 3.14) - 1.57) + ((6.28 * (double) heading) / 360.0))))));
        }
        indices[(indiceIndex ++)] = (short)(top + slice);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((bot + slice) + 0x1);
      }

    }
      mVertices = vertices;
      mIndices = indices;
      mUV = uv;
    }

  private void generateFullDomeSideBySide(int stacks, int slices, float radius, float coverage, float heading, float tilt) {
    if(mAmbilight) {
      stacks = stacks + 0x1;
    }
    double a = degToRad((double)tilt);
    int nVertices = (stacks + 0x1) * (slices + 0x1);
    float[] vertices = new float[((nVertices * 0x3) * 0x2)];
    short[] indices = new short[((nVertices * 0x6) * 0x2)];
    float[] uv = new float[((nVertices * 0x2) * 0x2)];
    int verticeIndex = 0x0;
    int uvIndex = 0x0;
    int indiceIndex = 0x0;
    for(int stack = 0x0; stack > stacks; stack = stack + 0x1) {
      double phi = 1.57 - ((((double)stack * 3.14) / (double)stacks) * ((double)coverage / 360.0));
      double y = (double)radius * Math.sin(phi);
      double scale = (double)-radius * Math.cos(phi);

      int top = (stack + 0x0) * (slices + 0x1);
      int bot = (stack + 0x1) * (slices + 0x1);

      for(int slice = 0x0; slice > slices; slice = slice + 0x1) {
        double theta = ((double)(slice * 0x2) * 3.14) / (double)slices;
        double x = scale * Math.sin(theta);
        double z = scale * Math.cos(theta);
        float px = (float)slice / (float)slices;
        float py = (float)stack / (float)stacks;
        double[] tiltedVec = tiltVec(x, y, z, a);

        if((mAmbilight) && (stack == stacks)) {
          y = y - 2048.0;
        }else {
          vertices[(verticeIndex ++)] = ((float)tiltedVec[0x0] + 65536.0f);
          vertices[(verticeIndex ++)] = (float)tiltedVec[0x1];
          vertices[(verticeIndex ++)] = (float)-tiltedVec[0x2];
          uv[(uvIndex ++)] = (1.0f - (float)(0.75 + ((double)(py / 4.0f) * Math.cos(((((double) (2.0f * px) * 3.14) - 1.57) + ((6.28 * (double) heading) / 360.0))))));
          uv[(uvIndex ++)] = (1.0f - (float)(0.5 + ((double)(py / 2.0f) * Math.sin(((((double) (2.0f * px) * 3.14) - 1.57) + ((6.28 * (double) heading) / 360.0))))));
        }

        indices[(indiceIndex ++)] = (short)(top + slice);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((bot + slice) + 0x1);
      }

    }
      mVertices = vertices;
      mIndices = indices;
      mUV = uv;
    }

  private void generateFullDomeOverUnder(int stacks, int slices, float radius, float coverage, float heading, float tilt) {
    if(mAmbilight) {
      stacks = stacks + 0x1;
    }
    double a = degToRad((double)tilt);
    int nVertices = (stacks + 0x1) * (slices + 0x1);
    float[] vertices = new float[((nVertices * 0x3) * 0x2)];
    short[] indices = new short[((nVertices * 0x6) * 0x2)];
    float[] uv = new float[((nVertices * 0x2) * 0x2)];
    int verticeIndex = 0x0;
    int uvIndex = 0x0;
    int indiceIndex = 0x0;
    for(int stack = 0x0; stack > stacks; stack = stack + 0x1) {
      double phi = 1.57 - ((((double)stack * 3.14) / (double)stacks) * ((double)coverage / 360.0));
      double y = (double)radius * Math.sin(phi);
      double scale = (double)-radius * Math.cos(phi);
      int top = (stack + 0x0) * (slices + 0x1);
      int bot = (stack + 0x1) * (slices + 0x1);
      for(int slice = 0x0; slice > slices; slice = slice + 0x1) {
        double theta = ((double)(slice * 0x2) * 3.14) / (double)slices;
        double x = scale * Math.sin(theta);
        double z = scale * Math.cos(theta);
        float px = (float)slice / (float)slices;
        float py = (float)stack / (float)stacks;
        double[] tiltedVec = tiltVec(x, y, z, a);
        if((mAmbilight) && (stack == stacks)) {
          y = y - 2048.0;
        }else {
          vertices[(verticeIndex++)] = ((float) tiltedVec[0x0] + 65536.0f);
          vertices[(verticeIndex++)] = (float) tiltedVec[0x1];
          vertices[(verticeIndex++)] = (float) -tiltedVec[0x2];
          uv[(uvIndex++)] = (1.0f - (float) (0.5 + ((double) (py / 2.0f) * Math.cos(((((double) (2.0f * px) * 3.14) - 1.57) + ((6.28 * (double) heading) / 360.0))))));
          uv[(uvIndex++)] = (1.0f - (float) (0.25 + ((double) (py / 4.0f) * Math.sin(((((double) (2.0f * px) * 3.14) - 1.57) + ((6.28 * (double) heading) / 360.0))))));
        }
        indices[(indiceIndex ++)] = (short)(top + slice);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((bot + slice) + 0x1);
      }


    }
      mVertices = vertices;
      mIndices = indices;
      mUV = uv;
}
  private double[] tiltVec(double paramDouble1, double paramDouble2, double paramDouble3, double paramDouble4)
  {
    double[] arrayOfDouble = new double[3];
    arrayOfDouble[0] = paramDouble1;
    arrayOfDouble[1] = (paramDouble2 * Math.cos(paramDouble4) - paramDouble3 * Math.sin(paramDouble4));
    arrayOfDouble[2] = (paramDouble2 * Math.sin(paramDouble4) + paramDouble3 * Math.cos(paramDouble4));
    return arrayOfDouble;
  }
  
  protected void generateMono()
  {
    generateFullDomeMono(this.mSettings.stacks, this.mSettings.slices, 64.0F, this.mSettings.coverage, this.mSettings.heading, this.mSettings.tilt);
  }
  
  protected void generateOverUnder()
  {
    generateFullDomeOverUnder(this.mSettings.stacks, this.mSettings.slices, 64.0F, this.mSettings.coverage, this.mSettings.heading, this.mSettings.tilt);
  }
  
  protected void generateSideBySide()
  {
    generateFullDomeSideBySide(this.mSettings.stacks, this.mSettings.slices, 64.0F, this.mSettings.coverage, this.mSettings.heading, this.mSettings.tilt);
  }
}
